#include "../http/http.hpp"
#include <openssl/ssl.h>
#include <openssl/err.h>

class HttpsServer :public HttpServer
{
    private:
        SSL_CTX* _ssl_ctx;//SSL_CTX
        std::string _cert_file;//证书文件路径
        std::string _key_file;//私钥路径
        std::map<int, SSL*> _ssl_connections;//套接字描述符和对应SSL连接

    public:
        HttpsServer(uint16_t port)
        :HttpServer(port)
        {
            InitServerSSL();//初始化SSL套件
        }
        virtual ~HttpsServer();

        void SetCertFile(std::string filepath)
        {
            _cert_file.swap(filepath);
        }

        void SetKeyFile(std::string filepath)
        {
            _key_file.swap(filepath);
        }

        void Listen()
        {

        }
    private:
        SSL* GetSSL(const PtrConnection&conn)
        {
            if(conn.get()==nullptr)
                return nullptr;
            return _ssl_connections[conn->Fd()];
        }

    private:
        void InitServerSSL()
        {
            //初始化OpenSSL套件
            //1.初始化Open SSL库本身
            SSL_library_init();

            //加载错误信息
            SSL_load_error_strings();

            //加载加密算法
            OpenSSL_add_all_algorithms();
        
            
            //2.创建SSL上下文
            _ssl_ctx = SSL_CTX_new(TLS_server_method());


            //3.加载私钥和服务器证书
            SSL_CTX_use_certificate_file(_ssl_ctx,_cert_file.c_str(),SSL_FILETYPE_PEM);
            SSL_CTX_use_PrivateKey_file(_ssl_ctx,_key_file.c_str(),SSL_FILETYPE_PEM);
        }
        
        void OnConnected(const PtrConnection&conn)
        {
            //通过共享ssl_ctx为每个套接字创建SSL对象
            SSL *new_ssl = SSL_new(_ssl_ctx);

            //将SSL对象与套接字关联
            SSL_set_fd(new_ssl, conn->GetFd());

            //本地存储
            _ssl_connections[conn->GetFd()] = new_ssl;
        }
        void OnMessage(const PtrConnection&conn,Buffer*buf)
        {
            //从缓冲区读取数据，判断是那种类型
            if(IsClientHello(buf))
            {
                //是客户端握手
                HandleClientHello(conn,buf);
            }
            else if(IsHttpRequest(buf))
            {
                //是http请求
                HandleHttpRequest();
            }
            else
            {
                //其他数据
            }
        }

        bool IsClientHello(Buffer*buf)
        {
            // 检测是否是ClientHello

            if(buf == nullptr)
            {
                ERR_LOG("IsClientHello::Buffer*为nullptr");
                return false;
            }


            if (buf->ReadAbleSize() < 6) return false;
            //报文过短直接返回

            const char* data = buf->GetLine().c_str();
            //转化为char的目的是一个字节一个字节地读取

            uint8_t type = data[0];
            uint16_t version = (data[1] << 8) | data[2];
            uint16_t length = (data[3] << 8) | data[4];

            if(20 == type && (0x0301 == version || 0x0302 == version || 0x0303))
            {
                return true;
            }

            return false;
        }

        bool IsHttpRequest(Buffer*buf)
        {
            //检测是否是http请求

            if(buf == nullptr)
            {
                ERR_LOG("IsHttpRequest::Buffer*为nullptr");
                return false;
            }

            if (buf->ReadAbleSize() < 4) 
                return false;
            //为什么是4？
            //因为请求头部最少3

            char *data = buf->ReadPosition();
            
            // 检查是否是 HTTP 请求行
            if(strncmp(data,"GET",4) ||
                strncmp(data,"POST",4) ||
                strncmp(data,"PUT",4) ||
                strncmp(data,"HEAD",4) ||
                strncmp(data,"DELETE",6))
                return true;

            return false;
        }

        //处理http请求
        void HandleHttpRequest(const PtrConnection&conn,Buffer*buf)
        {

        }


        //收到客户端握手，服务器握手
        void HandleClientHello(const PtrConnection&conn,Buffer*buf)
        {

            if(buf == nullptr)
            {
                ERR_LOG("HandleClientHello::Buffer*为nullptr");
                return;
            }

            //获取ssl
            SSL *ssl = _ssl_connections[conn->GetFd()];
            if(nullptr == ssl)
            {
                ERR_LOG("ssl为空nullptr");
                return ;
            }

            //判断是否连接完成
            if(SSL_is_init_finished(ssl))
            {
                int ret = SSL_accept(ssl);
                if(0 == ret)
                {
                    ERR_LOG("HandleHandShake::SSL_accept失败");
                    return;
                }
                else if(1 == ret)
                {
                    //握手成功
                    ParseHttpsMsg(ssl,conn,buf);
                }
                else
                {
                    int ssl_err = SSL_get_error(ssl,ret);

                    switch(ssl_err)
                    {
                    case SSL_ERROR_WANT_READ:
                        //需要更多客户端数据
                        INF_LOG("SSL握手需要更多客户端数据，等待读取");
                        break;
                    case SSL_ERROR_WANT_WRITE:
                        //需要写入响应
                        INF_LOG("SSL握手需要写入响应");
                        break;
                    case SSL_ERROR_ZERO_RETURN:
                        //连接被客户端关闭
                        ERR_LOG("客户端关闭连接");
                        break;
                    default:
                        //其他错误
                        DBG_LOG("SSL握手错误: "/* + std::to_string(ssl_err)*/);
                        break;
                    } 
                }
            }
        }

        #define DECRDATASIZE 4096

        //https协议解析
        void ParseHttpsMsg(SSL*ssl,const PtrConnection&conn,Buffer*buf)
        {
            //1.参数检查
            //2.检查缓冲区数据
            //3.解密数据
            //4.处理解密后的数据

            if(nullptr == ssl)
            {
                ERR_LOG("HandlePostHandshake::ssl = nullptr!");
                return;
            }
            if(nullptr == buf)
            {
                ERR_LOG("HandlePostHandshake::buf = nullptr!");
                return;
            }

            if(buf->ReadAbleSize() > 0)
            {
                char buffer[DECRDATASIZE];//临时缓冲区
                int bytes_read = SSL_read(ssl, buffer, sizeof(buffer));
                if(bytes_read > 0)
                {
                    ProcessDecryptedData(conn,buffer);
                }
                else if(bytes_read == 0)
                {
                    //SSL读取完成
                    INF_LOG("SSL读取完成");
                }
                else
                {
                    //读取错误
                    int ssl_err = SSL_get_error(ssl,bytes_read);
                    ERR_LOG("SSL读取错误");
                }
            }
            else
            {
                //缓冲区中没有数据
                return;
            }
        }

        //处理解密后的数据
        void ProcessDecryptedData(const PtrConnection&conn,const char*buf)
        {
            if(nullptr == buf)
            {
                ERR_LOG("ProcessDecryptedData::buf = nullptr!");
                return;
            }

            Buffer* decrypted_buffer = new Buffer(buf);//内存泄漏
            if (IsHttpRequest(decrypted_buffer))
            {
                HandleHttpRequest(conn,decrypted_buffer);
            }
            else
            {
                //非http请求数据
            }
            // 清理内存
            delete decrypted_buffer;
        }
};